/**
 * @file mysql_orm.cpp
 * @brief MySQL ORM辅助类实现
 * @author liyingcheng <1871304538@qq.com>
 * @date 2025-10-12
 */

#include "database/mysql_orm.h"
#include "database/mysql_helper.h"
#include "LoggerManager.h"
#include <sstream>

namespace cpp_backend
{
    namespace database
    {

        using namespace logger;

        // ============================================
        // 查询操作
        // ============================================

        nlohmann::json MySQLORM::FindOne(const std::string &table,
                                         const std::string &condition)
        {
            try
            {
                std::string sql = "SELECT * FROM " + table;
                if (!condition.empty())
                {
                    sql += " WHERE " + condition;
                }
                sql += " LIMIT 1";

                auto result = MySQLHelper::Query(sql);
                if (result.is_array() && !result.empty())
                {
                    return result[0];
                }
                return nlohmann::json(nullptr);
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "FindOne failed: " << e.what();
                return nlohmann::json(nullptr);
            }
        }

        nlohmann::json MySQLORM::FindAll(const std::string &table,
                                         const std::string &condition,
                                         const std::string &order_by,
                                         int limit)
        {
            try
            {
                std::string sql = "SELECT * FROM " + table;

                if (!condition.empty())
                {
                    sql += " WHERE " + condition;
                }

                if (!order_by.empty())
                {
                    sql += " ORDER BY " + order_by;
                }

                if (limit > 0)
                {
                    sql += " LIMIT " + std::to_string(limit);
                }

                return MySQLHelper::Query(sql);
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "FindAll failed: " << e.what();
                return nlohmann::json::array();
            }
        }

        nlohmann::json MySQLORM::FindById(const std::string &table,
                                          int64_t id,
                                          const std::string &id_field)
        {
            std::string condition = id_field + " = " + std::to_string(id);
            return FindOne(table, condition);
        }

        // ============================================
        // 插入操作
        // ============================================

        int64_t MySQLORM::Insert(const std::string &table,
                                 const nlohmann::json &data)
        {
            try
            {
                if (!data.is_object() || data.empty())
                {
                    LOG_ERROR << "Insert: invalid data";
                    return -1;
                }

                std::vector<std::string> fields;
                std::string values = JsonToValues(data, fields);

                std::ostringstream sql;
                sql << "INSERT INTO " << table << " (";

                for (size_t i = 0; i < fields.size(); ++i)
                {
                    if (i > 0)
                        sql << ", ";
                    sql << "`" << fields[i] << "`";
                }

                sql << ") VALUES (" << values << ")";

                return MySQLHelper::Insert(sql.str());
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "Insert failed: " << e.what();
                return -1;
            }
        }

        int MySQLORM::BatchInsert(const std::string &table,
                                  const nlohmann::json &data_list)
        {
            try
            {
                if (!data_list.is_array() || data_list.empty())
                {
                    LOG_ERROR << "BatchInsert: invalid data";
                    return -1;
                }

                // 从第一条记录获取字段列表
                std::vector<std::string> fields;
                for (auto it = data_list[0].begin(); it != data_list[0].end(); ++it)
                {
                    fields.push_back(it.key());
                }

                std::ostringstream sql;
                sql << "INSERT INTO " << table << " (";

                for (size_t i = 0; i < fields.size(); ++i)
                {
                    if (i > 0)
                        sql << ", ";
                    sql << "`" << fields[i] << "`";
                }

                sql << ") VALUES ";

                for (size_t i = 0; i < data_list.size(); ++i)
                {
                    if (i > 0)
                        sql << ", ";

                    std::vector<std::string> dummy_fields;
                    sql << "(" << JsonToValues(data_list[i], dummy_fields) << ")";
                }

                int rows = MySQLHelper::Execute(sql.str());
                return rows;
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "BatchInsert failed: " << e.what();
                return -1;
            }
        }

        // ============================================
        // 更新操作
        // ============================================

        int MySQLORM::Update(const std::string &table,
                             const nlohmann::json &data,
                             const std::string &condition)
        {
            try
            {
                if (!data.is_object() || data.empty())
                {
                    LOG_ERROR << "Update: invalid data";
                    return -1;
                }

                if (condition.empty())
                {
                    LOG_ERROR << "Update: condition is required";
                    return -1;
                }

                std::string set_clause = JsonToSetClause(data);

                std::string sql = "UPDATE " + table +
                                  " SET " + set_clause +
                                  " WHERE " + condition;

                return MySQLHelper::Execute(sql);
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "Update failed: " << e.what();
                return -1;
            }
        }

        int MySQLORM::UpdateById(const std::string &table,
                                 int64_t id,
                                 const nlohmann::json &data,
                                 const std::string &id_field)
        {
            std::string condition = id_field + " = " + std::to_string(id);
            return Update(table, data, condition);
        }

        // ============================================
        // 删除操作
        // ============================================

        int MySQLORM::Delete(const std::string &table,
                             const std::string &condition)
        {
            try
            {
                if (condition.empty())
                {
                    LOG_ERROR << "Delete: condition is required for safety";
                    return -1;
                }

                std::string sql = "DELETE FROM " + table + " WHERE " + condition;
                return MySQLHelper::Execute(sql);
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "Delete failed: " << e.what();
                return -1;
            }
        }

        int MySQLORM::DeleteById(const std::string &table,
                                 int64_t id,
                                 const std::string &id_field)
        {
            std::string condition = id_field + " = " + std::to_string(id);
            return Delete(table, condition);
        }

        // ============================================
        // 统计操作
        // ============================================

        int64_t MySQLORM::Count(const std::string &table,
                                const std::string &condition)
        {
            try
            {
                std::string sql = "SELECT COUNT(*) as count FROM " + table;
                if (!condition.empty())
                {
                    sql += " WHERE " + condition;
                }

                auto result = MySQLHelper::Query(sql);
                if (result.is_array() && !result.empty() && result[0].contains("count"))
                {
                    // 尝试int64_t，如果失败则尝试int
                    try
                    {
                        return result[0]["count"].get<int64_t>();
                    }
                    catch (...)
                    {
                        return result[0]["count"].get<int>();
                    }
                }
                return -1;
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "Count failed: " << e.what();
                return -1;
            }
        }

        bool MySQLORM::Exists(const std::string &table,
                              const std::string &condition)
        {
            return Count(table, condition) > 0;
        }

        // ============================================
        // 分页查询
        // ============================================

        nlohmann::json MySQLORM::Paginate(const std::string &table,
                                          int page,
                                          int page_size,
                                          const std::string &condition,
                                          const std::string &order_by)
        {
            try
            {
                if (page < 1 || page_size < 1)
                {
                    LOG_ERROR << "Paginate: invalid page or page_size";
                    return nlohmann::json::object();
                }

                // 查询总数
                int64_t total = Count(table, condition);
                if (total < 0)
                {
                    return nlohmann::json::object();
                }

                // 计算偏移量
                int offset = (page - 1) * page_size;

                // 查询数据
                std::string sql = "SELECT * FROM " + table;
                if (!condition.empty())
                {
                    sql += " WHERE " + condition;
                }
                if (!order_by.empty())
                {
                    sql += " ORDER BY " + order_by;
                }
                sql += " LIMIT " + std::to_string(page_size) +
                       " OFFSET " + std::to_string(offset);

                auto data = MySQLHelper::Query(sql);

                // 构建分页结果
                nlohmann::json result;
                result["data"] = data;
                result["pagination"] = {
                    {"page", page},
                    {"page_size", page_size},
                    {"total", total},
                    {"total_pages", (total + page_size - 1) / page_size}};

                return result;
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "Paginate failed: " << e.what();
                return nlohmann::json::object();
            }
        }

        // ============================================
        // 事务操作
        // ============================================

        bool MySQLORM::Transaction(std::function<bool(sql::Connection *)> callback)
        {
            try
            {
                MySQLConnectionGuard guard(3000);
                if (!guard.IsValid())
                {
                    LOG_ERROR << "Transaction: failed to get connection";
                    return false;
                }

                sql::Connection *conn = guard.Get();

                // 开始事务
                conn->setAutoCommit(false);

                try
                {
                    // 执行回调
                    bool success = callback(conn);

                    if (success)
                    {
                        conn->commit();
                        conn->setAutoCommit(true);
                        LOG_DEBUG << "Transaction committed";
                        return true;
                    }
                    else
                    {
                        conn->rollback();
                        conn->setAutoCommit(true);
                        LOG_DEBUG << "Transaction rolled back by callback";
                        return false;
                    }
                }
                catch (const std::exception &e)
                {
                    conn->rollback();
                    conn->setAutoCommit(true);
                    LOG_ERROR << "Transaction exception: " << e.what();
                    return false;
                }
            }
            catch (const std::exception &e)
            {
                LOG_ERROR << "Transaction failed: " << e.what();
                return false;
            }
        }

        // ============================================
        // 辅助函数
        // ============================================

        std::string MySQLORM::JsonToSetClause(const nlohmann::json &data)
        {
            std::ostringstream oss;
            bool first = true;

            for (auto it = data.begin(); it != data.end(); ++it)
            {
                if (!first)
                {
                    oss << ", ";
                }
                first = false;

                oss << "`" << it.key() << "` = ";

                if (it.value().is_string())
                {
                    oss << "'" << EscapeString(it.value().get<std::string>()) << "'";
                }
                else if (it.value().is_null())
                {
                    oss << "NULL";
                }
                else
                {
                    oss << it.value();
                }
            }

            return oss.str();
        }

        std::string MySQLORM::JsonToValues(const nlohmann::json &data,
                                           std::vector<std::string> &fields)
        {
            std::ostringstream oss;
            bool first = true;

            fields.clear();

            for (auto it = data.begin(); it != data.end(); ++it)
            {
                fields.push_back(it.key());

                if (!first)
                {
                    oss << ", ";
                }
                first = false;

                if (it.value().is_string())
                {
                    oss << "'" << EscapeString(it.value().get<std::string>()) << "'";
                }
                else if (it.value().is_null())
                {
                    oss << "NULL";
                }
                else
                {
                    oss << it.value();
                }
            }

            return oss.str();
        }

        std::string MySQLORM::EscapeString(const std::string &str)
        {
            std::string result;
            result.reserve(str.length());

            for (char c : str)
            {
                switch (c)
                {
                case '\'':
                    result += "\\'";
                    break;
                case '\"':
                    result += "\\\"";
                    break;
                case '\\':
                    result += "\\\\";
                    break;
                case '\0':
                    result += "\\0";
                    break;
                case '\n':
                    result += "\\n";
                    break;
                case '\r':
                    result += "\\r";
                    break;
                default:
                    result += c;
                    break;
                }
            }

            return result;
        }

    } // namespace database
} // namespace file_server
